package drds.plus.sql_process.abstract_syntax_tree.configuration.manager;


import drds.plus.common.lifecycle.AbstractLifecycle;
import drds.plus.common.model.DataNode;
import drds.plus.sql_process.abstract_syntax_tree.configuration.TableMetaData;
import drds.plus.sql_process.rule.RouteOptimizer;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;

import java.util.Collection;

/**
 * 基于repo的{@linkplain SchemaManager}的委托实现
 */
@Slf4j
public class RepositorySchemaManager extends AbstractLifecycle implements SchemaManager {
    @Override
    public Logger log() {
        return log;
    }

    protected RouteOptimizer routeOptimizer = null;
    private RepositorySchemaManager delegate;
    private boolean isDelegate;
    private StaticSchemaManager local;
    private DataNode dataNode;

    public RouteOptimizer getRouteOptimizer() {
        return this.routeOptimizer;
    }

    public void setRouteOptimizer(RouteOptimizer routeOptimizer) {
        this.routeOptimizer = routeOptimizer;
    }

    protected void doInit() {
        if (local != null) {
            local.init();
        }

        if (!isDelegate) {
            // bdb, mysql, demo;
            RepositorySchemaManager delegate = null;
            if (dataNode.getRepositoryType().name().equals("mysql")) {
                try {
                    delegate = (RepositorySchemaManager) Class.forName("RepositorySchemaManagerImpl").newInstance();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            } else if (dataNode.getRepositoryType().name().equals("bdb")) {
                try {
                    delegate = (RepositorySchemaManager) Class.forName("RepositorySchemaManagerImpl").newInstance();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
            //share_delegate = ExtensionLoader.load(RepositorySchemaManager.class, dataNode.getRepositoryType().columnName());
            delegate.setDataNode(dataNode);
            delegate.setDelegate(true);
            delegate.setRouteOptimizer(routeOptimizer);
            delegate.init();
        }
    }

    public final TableMetaData getTableMetaData(String tableName) {
        return getTable(tableName, null);
    }

    public final TableMetaData getTable(String logicalTableName, String actualTableName) {
        TableMetaData tableMetaData = null;


        if (local != null) {// 本地如果开启了，先找本地
            tableMetaData = local.getTableMetaData(logicalTableName);
        }

        if (tableMetaData == null) {// 本地没有
            tableMetaData = delegate.getTable0(logicalTableName, actualTableName);
        }

        return tableMetaData;
    }

    public final void putTable(String tableName, TableMetaData tableMetaData) {
        if (local != null) {// 本地如果开启了，先处理本地
            local.putTable(tableName, tableMetaData);
        } else {
            delegate.putTable(tableName, tableMetaData);
        }
    }

    public Collection<TableMetaData> getAllTables() {
        if (local != null) {// 本地如果开启了，先处理本地
            return local.getAllTables();
        } else {
            throw new UnsupportedOperationException();
        }
    }

    /**
     * 需要各Repo来实现
     */
    protected TableMetaData getTable0(String logicalTableName, String actualTableName) {
        throw new UnsupportedOperationException("对应repo需要实现");
    }

    protected void doDestroy() {
        if (local != null && local.isInited()) {
            local.destroy();
        }

        if (!isDelegate) {
            delegate.destroy();
        }
    }


    public DataNode getDataNode() {
        return dataNode;
    }

    public void setDataNode(DataNode dataNode) {
        this.dataNode = dataNode;
    }

    public void setLocal(StaticSchemaManager local) {
        this.local = local;
    }

    public void setDelegate(boolean isDelegate) {
        this.isDelegate = isDelegate;
    }

    public void reload() {
        if (this.local != null) {
            local.reload();
        }

        if (this.delegate != null) {
            this.delegate.reload();
        }
    }

}
